using AutoMapper;
using B.S.Medical.Api.Read.Application.Command.Register;
using B.S.Medical.Api.Read.DTOS.Fee;
using B.S.Medical.Domain.Medical;
using B.S.Medical.Infrastructure.Interface;
using MediatR;
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Collections.Generic;

namespace B.S.Medical.Api.Read.Application.Handler.Register
{
    public class ShowRegisterFeeDetailHandler : IRequestHandler<ShowRegisterFeeDetailCommand, RegisterFeeDetailDto>
    {
        private readonly IBaseRepository<RegisterModel> _registerRepository;
        private readonly IBaseRepository<PatientModel> _patientRepository;
        private readonly IBaseRepository<RegisterDetailModel> _registerDetailRepository;
        private readonly IBaseRepository<DrugModel> _drugRepository;

        public ShowRegisterFeeDetailHandler(
            IBaseRepository<RegisterModel> registerRepository,
            IBaseRepository<PatientModel> patientRepository,
            IBaseRepository<RegisterDetailModel> registerDetailRepository,
            IBaseRepository<DrugModel> drugRepository)
        {
            _registerRepository = registerRepository;
            _patientRepository = patientRepository;
            _registerDetailRepository = registerDetailRepository;
            _drugRepository = drugRepository;
        }

        public async Task<RegisterFeeDetailDto> Handle(ShowRegisterFeeDetailCommand request, CancellationToken cancellationToken)
        {
            var register = await _registerRepository.GetValue(request.RegisterId);
            var patient = await _patientRepository.GetValue(register.PatientId);

            string gender = GetGenderFromIdCard(patient.IdCard);
            int age = GetAgeFromIdCard(patient.IdCard);

            var details = _registerDetailRepository.GetAll().Where(x => x.RegisterId == request.RegisterId).ToList();
            var firstDetail = details.OrderBy(x => x.CreateTime).FirstOrDefault();

            var drugIds = details.Where(x => x.DrugId.HasValue).Select(x => x.DrugId.Value).ToList();
            var drugs = _drugRepository.GetAll().Where(x => drugIds.Contains(x.Id)).ToList();

            var items = details.Select(d =>
            {
                string itemName = d.ItemType == "药品"
                    ? drugs.FirstOrDefault(dr => dr.Id == d.DrugId)?.DrugName ?? "未知"
                    : d.ItemType;
                decimal unitPrice = d.ItemType == "药品"
                    ? drugs.FirstOrDefault(dr => dr.Id == d.DrugId)?.UnitPrice ?? 0
                    : (d.Quantity > 0 ? d.Amount / d.Quantity : d.Amount);
                return new FeeItemDto
                {
                    ItemName = itemName,
                    UnitPrice = unitPrice,
                    Quantity = d.Quantity,
                    Amount = d.Amount
                };
            }).ToList();

            return new RegisterFeeDetailDto
            {
                PatientName = patient.Name,
                Gender = gender,
                Age = age,
                ReportDate = firstDetail?.CreateTime ?? DateTime.MinValue,
                TotalAmount = details.Sum(x => x.Amount),
                Items = items
            };
        }

        private string GetGenderFromIdCard(string idCard)
        {
            if (string.IsNullOrEmpty(idCard) || idCard.Length < 17) return "未知";
            int genderNum = int.Parse(idCard.Substring(16, 1));
            return genderNum % 2 == 0 ? "女" : "男";
        }

        private int GetAgeFromIdCard(string idCard)
        {
            if (string.IsNullOrEmpty(idCard) || idCard.Length < 14) return 0;
            int year = int.Parse(idCard.Substring(6, 4));
            int month = int.Parse(idCard.Substring(10, 2));
            int day = int.Parse(idCard.Substring(12, 2));
            var birth = new DateTime(year, month, day);
            var now = DateTime.Now;
            int age = now.Year - birth.Year;
            if (now.Month < birth.Month || (now.Month == birth.Month && now.Day < birth.Day))
                age--;
            return age;
        }
    }
} 